


#include <Windows.h>
#include <process.h>
#include <io.h>
#include <stdio.h>
#include <ctime>
#include <string>
#include <iostream>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <iomanip>

using namespace std;

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>

#include "AutoLock.h"

#include "Log.h"

void __ToString(const wstring& ws, string& out, DWORD cp){
	out = "";
	if(!ws.empty()){
		DWORD dwMinSize = WideCharToMultiByte(cp, NULL,ws.c_str(),-1,NULL,0,NULL,FALSE);
		if(dwMinSize){
			out.resize(dwMinSize, 0);
			int n =WideCharToMultiByte(cp, NULL, ws.c_str(), -1, &out[0], dwMinSize,NULL,FALSE);
			if(n >0){
				out.resize(n-1);
			}else{
				out = "";
			}
		}
	}
}
void __ToWString(const string& s, wstring& out, DWORD cp){
	out = L"";
	if(!s.empty()){
		int dwMinSize = MultiByteToWideChar(cp, 0, s.c_str(), -1, NULL, 0);
		if(dwMinSize > 0){
			out.resize(dwMinSize, 0);
			int n = MultiByteToWideChar(cp, 0, s.c_str(), -1, &out[0], dwMinSize); 
			if(n >0){
				out.resize(n-1);
			}else{
				out = L"";
			}
		}
	}
}

bool Logger::toConsole=true;
bool Logger::toDebugWindow=true;
string Logger::filename;

Logger& Logger::get(int level){
	static Logger lg;
	lg<<Timestamp<<ThreadID;
	switch(level){
		case 0:
			lg<<"[INFO] ";
			break;
		case 1:
			lg<<"[WARN] ";
			break;
		case 2:
			lg<<"[ERROR] ";
			break;
		case 3:
			lg<<"[FATAIL] ";
			break;
	}
	return lg;
}

Logger::Logger(string filename, bool toConsole, bool toDebugWindow){
	this->filename = filename;
	this->toConsole = toConsole;
	this->toDebugWindow = toDebugWindow;
}
void Logger::SetLogFile(string logfile){
	Logger::filename = logfile;
}
void Logger::SetToConsole(bool toConsole){
	Logger::toConsole = toConsole;
}
void Logger::SetToDebugWindow(bool toDebugWindow){
	Logger::toDebugWindow = toDebugWindow;
}
size_t Logger::Length()const{
	return buf.length();
}


void Logger::Append(const string& s, UINT cp){
	ThreadLock lock("Logger::Append_string_cp");
	if(cp == GetACP()){
		buf.append(s);
	}else{
		wstring ws;
		__ToWString(s, ws, cp);
		string ss;
		__ToString(ws, ss, GetACP());
		buf.append(ss);
	}
	if(Length() >=64){
		Flush();
	}
}
void Logger::Append(const wstring& ws){
	string s;
	__ToString(ws, s, GetACP());
	Append(s);
}
void Logger::Flush(){
	if(toDebugWindow){
		::OutputDebugStringA(buf.c_str());
	}
	if(toConsole){
		cout<<buf<<flush;
	}
	ThreadLock lock("Logger::Flush");
	if(!filename.empty()){
		FILE* f = 0;
		if(f= fopen(filename.c_str(), "at")){
			fwrite(buf.c_str(), buf.length(), 1, f);
			fclose(f);
		}
	}
	buf.clear();
}

////Logger& Info(Logger& slog){
////	slog<<"INFO : ";
////	return slog;
////}
////Logger& Error(Logger& slog){
////	slog<<"ERROR: ";
////	return slog;
////}
////Logger& Warn(Logger& slog){
////	slog<<"WARN : ";
////	return slog;
////}
Logger& Timestamp(Logger& slog){
	SYSTEMTIME t = {0};
	GetSystemTime(&t);
	slog.Append(boost::str(boost::format("[%4d-%02d-%02d %02d:%02d:%02d %03d] ")%t.wYear %t.wMonth %t.wDay %t.wHour %t.wMinute %t.wSecond %t.wMilliseconds));
	return slog;
}
Logger& ThreadID(Logger& slog){
	slog.Append(boost::str(boost::format("[%06d] ") % GetCurrentThreadId()));
	return slog;
}

Logger& endl(Logger& slog){
	slog.Append("\n");
	slog.Flush();
	return slog;
}
Logger& flush(Logger& slog){
	slog.Flush();
	return slog;
}


Logger& operator << (Logger& slog, Logger& (*pFun)(Logger&) ){
	return (*pFun)(slog);
}

Logger& operator << (Logger& slog, bool val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, char val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, unsigned char val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, short val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, unsigned short val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
//vs Ĭ����wchar_tΪ��������!!
Logger& operator << (Logger& slog, wchar_t val){
	slog.Append(wstring(&val, 1));
	return slog;
}
Logger& operator << (Logger& slog, int val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, unsigned int val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, long val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, unsigned long val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}

Logger& operator << (Logger& slog, float val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, double val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}
Logger& operator << (Logger& slog, long double val){
	slog.Append(boost::lexical_cast<string>(val));
	return slog;
}

Logger& operator << (Logger& slog, const char* s){
	slog.Append(s);
	return slog;
}
Logger& operator << (Logger& slog, const string& s){
	slog.Append(s);
	return slog;
}

Logger& operator << (Logger& slog, const wchar_t* ws){
	slog.Append(ws);
	return slog;
}
Logger& operator << (Logger& slog, const wstring& ws){
	slog.Append(ws);
	return slog;
}

Logger& operator << (Logger& slog, char* s){
	slog.Append(s);
	return slog;
}
Logger& operator << (Logger& slog, string& s){
	slog.Append(s);
	return slog;
}

Logger& operator << (Logger& slog, wchar_t* ws){
	slog.Append(ws);
	return slog;
}
Logger& operator << (Logger& slog, wstring& ws){
	slog.Append(ws);
	return slog;
}

